/*
 * WorldBoss.cpp
 *
 *  Created on: 2014. 1. 16.
 *      Author: jjaehuny
 */

#include "WorldBoss.h"

#include "../../macro.h"
#include "../../User.h"
#include "../../engine.h"

#include "../../NLogic/Battle.h"
#include "../../NLogic/Space.h"
#include "../../NLogic/Monster.h"
#include "../../NLogic/Status.h"

#include "../../NResource/Static.h"
#include "../../NResource/ValidResource.h"

namespace ProjectZ { namespace NProcess { namespace NCombat {

WorldBoss::WorldBoss() {
	// TODO Auto-generated constructor stub

}

WorldBoss::~WorldBoss() {
	// TODO Auto-generated destructor stub
}

void
WorldBoss::Attack(User * pUser, ::Network::Packet * pPacket)
{
	/*
	 * // 던전에서 공격
		CN_ATTACK_DUNGEON	0x0515
		{
			u8	u8effect;		// 데미지 이펙트 출력 여부(0 없음 , 1 있음)
			u32	damage_value;	// Damage value(0 : 공격 실패, 0보다 큰경우 공격 성공)
			u32	defender_gid;	// DEFENDER GID
			u8	defender_ismonster;	// DEFENDER의 몬스터여부(0:주인공 1:몬스터)
			u16	degree;			방향 벡터(보고있는 방향 0 : RIGHT, 90 : DOWN..)
			u8	statetype;		// 상태이상여부 상위 4bit / 백어택여부 하위4bit
			u8	ismonster;		// 공격자의 몬스터여부 (0 : 주인공 1: 몬스터)
			u32	attacker_gid;	// 공격자 GID
		}

		SN_ATTACK_DUNGEON	0x0516
		{
			u8	u8effect;		// 데미지 이펙트 출력 여부(0 없음 , 1 있음)
			u32	damage_value;	// Damage value(0 : 공격 실패, 0보다 큰경우 공격 성공)
			u32	defender_gid;	// DEFENDER GID
			u8	defender_ismonster;	// DEFENDER의 몬스터여부(0:주인공 1:몬스터)
			u32	defender_hp;	// DEFENDER의 데미지 반영 후 HP
			u16	degree;			방향 벡터(보고있는 방향 0 : RIGHT, 90 : DOWN..)
			u8	ismonster;		// 공격자의 몬스터여부 (0 : 주인공 1: 몬스터)
			u32	attacker_gid;	// 공격자 GID
		}
	 */

	Value clsValue;

	*pPacket >> clsValue.effect >> clsValue.damage_value >> clsValue.defender_gid;
	*pPacket >> clsValue.defender_ismonster >> clsValue.degree >> clsValue.statetype >> clsValue.ismonster >> clsValue.attacker_gid >> clsValue.attack_type;

	if (0 == clsValue.ismonster && 0 == clsValue.defender_ismonster) // ATTACK USER TO USER
	{
		DEBUGLOG("CN_ATTACK_DUNGEON::processSingleDungeion 0 == clsValue.ismonster && 0 == clsValue.defender_ismonster");
		return;
	}

//	int targetHP = 0;
	if (0 == clsValue.ismonster && 1 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (0 == clsValue.ismonster && 2 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (0 == clsValue.ismonster && 3 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (1 == clsValue.ismonster && 0 == clsValue.defender_ismonster) // attack user to monster
	{
		MonsterAttackUser(pUser, clsValue);
	}
	else if (1 == clsValue.ismonster && 1 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (1 == clsValue.ismonster && 2 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (1 == clsValue.ismonster && 3 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (2 == clsValue.ismonster && 0 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (2 == clsValue.ismonster && 1 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (2 == clsValue.ismonster && 2 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (2 == clsValue.ismonster && 3 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (3 == clsValue.ismonster && 0 == clsValue.defender_ismonster) // attack user to monster
	{
		MonsterAttackUser(pUser, clsValue);
	}
	else if (3 == clsValue.ismonster && 1 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (3 == clsValue.ismonster && 2 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (3 == clsValue.ismonster && 3 == clsValue.defender_ismonster) // attack user to monster
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (4 == clsValue.ismonster && 0 == clsValue.defender_ismonster)
	{
		MonsterAttackUser(pUser, clsValue);
	}
	else if (4 == clsValue.ismonster && 1 == clsValue.defender_ismonster)
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (4 == clsValue.ismonster && 2 == clsValue.defender_ismonster)
	{
		UserAttackMonster(pUser, clsValue);
	}
	else if (4 == clsValue.ismonster && 3 == clsValue.defender_ismonster)
	{
		UserAttackMonster(pUser, clsValue);
	}
	else
	{
	}
}

void
WorldBoss::UserAttackMonster(User * pUser, Value & value)
{
	NResource::ValidResource::Flyweight * pFly = NResource::Static::Instance().GetValid()->GetFly(pUser->GetCharacterInfo().level);
	if (NULL == pFly)
	{
		DEBUGLOG("%s NULL == pFly", __FUNCTION__);
		return;
	}

	if (pFly->_DAMAGES < value.damage_value)
	{
		DEBUGLOG("CHEATUSER %s pFly->_DAMAGES < damage_value  pFly->_DAMAGES : %d damage : %d GID : %d", __FUNCTION__, pFly->_DAMAGES, value.damage_value, pUser->GetUserSeq());
		return;
	}

	NLogic::Battle * pBattle = pUser->GetBattle();
	if (NULL == pBattle)
	{
		DEBUGLOG("%s NULL == pBattle", __FUNCTION__);
		return;
	}

	if (pBattle->GetData().HP <= 0)
	{
		DEBUGLOG("%s pBattle->GetData().HP <= 0", __FUNCTION__);
		return;
	}


	NLogic::Monster * pMonster = pUser->GetSpace()->GetMonster(value.defender_gid);
	if (NULL == pMonster)
	{
		DEBUGLOG("%s NULL == pMonster", __FUNCTION__);
		return;
	}

	// 보스를 공격한 경우....
	if (pMonster->GetData().tid == pUser->GetSpace()->GetData()._boss_tid)
	{
		pBattle->GetData()._worldBoss_Hited++;
		int point = value.damage_value / 100;
		pBattle->GetData()._worldBoss_Point += point;

		::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
		* pAck << value.effect;
		* pAck << value.damage_value;
		* pAck << value.defender_gid;
		* pAck << value.defender_ismonster;
		* pAck << static_cast<int32_t>(100);
		* pAck << value.degree;
		* pAck << value.ismonster;
		* pAck << value.attacker_gid;
		* pAck << value.attack_type;
		pAck->MakePacket(CMD_SN_ATTACK_DUNGEON);
		pUser->GetSpace()->SendAll(pAck);

		return;
	}

	int targetHP = 0;
	targetHP = pMonster->DecreaseHP( value.damage_value);
	if( targetHP == 0 )
	{
		if (pMonster->GetMonsterType() == NLogic::Monster::MonsterType::MONSTER)
		{
			pUser->GetSpace()->RemoveMonster( value.defender_gid);
			
			// Added by spencer(2014.07.14)
			// boss monster가 죽는 시간을 저장한다.
			pUser->GetSpace()->GetData()._finishtick = time(NULL);			
		}
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pAck << value.effect;
	* pAck << value.damage_value;
	* pAck << value.defender_gid;
	* pAck << value.defender_ismonster;
	* pAck << (int)targetHP;
	* pAck << value.degree;
	* pAck << value.ismonster;
	* pAck << value.attacker_gid;
	* pAck << value.attack_type;
	pAck->MakePacket(CMD_SN_ATTACK_DUNGEON);
	pUser->GetSpace()->SendAll(pAck);

	// 몬스터에 hp 정보 update 패킷 전송
	::Network::Packet * pNoti = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pNoti << value.defender_gid;
	* pNoti << targetHP;
	pNoti->MakePacket(CMD_SN_DUNGEON_UPDATE_MOB_HP);
	pUser->GetSpace()->SendAll(pNoti);
}

void
WorldBoss::MonsterAttackUser(User * pUser, Value & value)
{
	NLogic::Space * pSpace = pUser->GetSpace();
	if (NULL == pSpace)
	{
		DEBUGLOG("%s NULL == pSpace", __FUNCTION__);
		return;
	}

	User * pTarget = pSpace->FindUser(value.defender_gid);
	if (NULL == pTarget)
	{
		DEBUGLOG("%s NULL == pTarget", __FUNCTION__);
		return;
	}

	if (true == pUser->GetSpace()->GetEndEungeon())
	{
		DEBUGLOG("%s true == pUser->GetSpace()->GetEndEungeon()", __FUNCTION__);
		return;
	}

	NLogic::Battle * pBattle = pTarget->GetBattle();
	if (NULL == pBattle)
	{
		DEBUGLOG("%s NULL == pBattle", __FUNCTION__);
		return;
	}

	if (0 == pBattle->GetData().HP) return;

	if (pBattle->GetData().HP <= value.damage_value)
	{
		pBattle->GetData().HP = 0;
		
		// Added by spencer(2014.07.14)
		// 타겟 유저가 죽는 시간을 저장한다.
		pTarget->SetDeadTime( time(NULL) );		

		DEBUGLOG("%s %d HPISZERO USERSEQ : %d WORLDBOSS", __FUNCTION__, __LINE__, pTarget->GetUserSeq());
	}
	else
	{
		pBattle->GetData().HP -= value.damage_value;
	}

	::Network::Packet * pAck = ::Network::GETPACKETPOOL()->SEND_NEW();
	* pAck << value.effect;
	* pAck << value.damage_value;
	* pAck << value.defender_gid;
	* pAck << value.defender_ismonster;
	* pAck << static_cast<int32_t>(pBattle->GetData().HP);
	* pAck << value.degree;
	* pAck << value.ismonster;
	* pAck << value.attacker_gid;
	* pAck << value.attack_type;
	pAck->MakePacket(CMD_SN_ATTACK_DUNGEON);
	pUser->GetSpace()->SendAll(pAck);

	// 전투팻 상태이상 ...
	if (0 >= pBattle->GetData().HP)
	{
		NLogic::Status * pStatus = pTarget->GetStatus();
		if (NULL != pStatus)
		{
			NLogic::Status::Data * pData = pStatus->GetStausData(NLogic::Status::StatusType::BATTLEPET_REBIRTH);
			if (NULL != pData && true == pData->_bRegist)
			{
				pBattle->GetData().HP = pBattle->GetData().HP_MAX * pData->_value / 100;

				::Network::Packet * rebirth = ::Network::GETPACKETPOOL()->SEND_NEW();
				* rebirth << static_cast<uint8_t>(0);
				* rebirth << pTarget->GetUserSeq();
				* rebirth << pBattle->GetData().HP;
				rebirth->MakePacket(CMD_SC_REBIRTH_DIRECT);
				pSpace->SendAll(rebirth);

				pData->Clear();
			}
		}
	}
}

} /*NCombat*/ } /*NProcess*/ } /*ProjectZ*/

